#include <iostream>
#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
#include <SDL/SDL_ttf.h>
#include <stdlib.h>
#include <sys/types.h>  // socket
#include <sys/socket.h> // socket, inet_addr
#include <netinet/in.h> // inet_addr
#include <arpa/inet.h>   // inet_addr
#include <unistd.h>      // close
#include <fstream>
#include <pthread.h>
#include <signal.h>
#include <fcntl.h>
#include <limits.h>
#include <string.h>

#include "headers/sdl.h"
#include "headers/socket.h"
#include "headers/funciones_generales.h"
#include "headers/pthread.h"

#define TAMBUF 1024

using namespace std;



ofstream f_torneo("torneo.txt");

void * th_f_torneo(void *);
void * th_f_dibujar(void *);
void * th_f_capturar_teclas(void *);


pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond_dibujar = PTHREAD_COND_INITIALIZER;
pthread_cond_t cond_capturar_tecla = PTHREAD_COND_INITIALIZER;




void sdl_presentacion();
void sdl_esperando_inscripcion(void);
void carga_inicial();


void dibujar_movimiento_mario(void);
//void dibujar_movimiento_princesa(void);
//void dibujar_movimiento_mono(void);
//void dibujar_movimiento_barril_fuego(void);
//void dibujar_movimiento_fuego(void);
//void dibujar_movimiento_barril(void);

void refrescar_pantalla_mario(void);
void dibujar_fondo(void);

#define WIDTH 640
#define HEIGHT 480
#define BPP 24
#define MARIO_W  20 // ancho de mario
#define MARIO_H  30 // alto de mario
#define PRINCESA_W 20 // ancho de la princesa
#define PRINCESA_H 30  // alto de la princesa

SDL_Surface *presentacion, *pantalla,*fondo,*esperando, *mario,*princesa;
SDL_Rect src_pres,dest_pres,src_mario,dest_mario,src_fondo,dest_fondo;
SDL_Rect src_princesa,dest_princesa;

SDL_Event evento_presentacion;
SDL_Event evento_mario;
SDL_Event evento_princesa;

// para los movimientos de los personajes
struct movimientos {
    int x,y;
};


struct movimientos mario_movi;
struct movimientos luis_movi;

// Permite definir que dibujar. th_f_dibujar()
char dibujar[20];
char tecla[20];

pthread_t th_torneo; // thread para servidor de torneo
pthread_t th_dibujar;
pthread_t th_capturar_teclas;

// para socket
int socket_fd;
char buffer[TAMBUF];

int sock_aceptar;   // socket de conexion

int listen_socket_SP;
int socket_ST;

struct sockaddr_in listen_address, con_address;
socklen_t con_addr_len;


// tipo_senial = 1 crear imagen
//   identifacador[] = jug1, jug2

typedef struct {
	int tipo_senial; //mov
	char identificador[5]; //jug1
	int senial; //izq
	int x;   // posicion x
	int y;   // posicion y
	char colision[5]; //mono
        char tecla[2];
} envio;

envio recepcion[4];
envio recepcion_juego;



char imagenes[][40] = {"../img/mario_der1.png","../img/luis_izq1.png","../img/mono_888.png","../img/princesa_izq1.png","../img/mario_der2","../img/mario_der3png","mario_izq1.png","mario_izq2.png","mario_izq3.png","luis_izq2.png","luis_izq3.png","luis_der1.png","luis_der2.png","luis_der3.png"};




//int main(int argc, char *argv[]) { // Codigo maxi.


 /* Codigo para usar en eclipse */
int main() {

	int argc = 2;
	char *argv[2] = { "./cliente", "mario" };

	if ((chdir("src")) < 0) {
		perror("Cambio de directorio falló...");
	    exit(EXIT_FAILURE);
	}

	char buff[PATH_MAX + 1];
	char*  dir_act = getcwd(buff, sizeof(buff));
	printf("%s\n", dir_act);




	// debe ingresar su nombre
	if (argc != 2)
		return ayuda();

	// dibuja la presentacion
	sdl_presentacion();

	// Se anota al torneo
	pthread_create(&th_torneo, NULL, th_f_torneo, (void*) argv[1]);
	pthread_create(&th_dibujar, NULL, th_f_dibujar, NULL);
	pthread_create(&th_capturar_teclas, NULL, th_f_capturar_teclas, NULL);

	// el main espera la finalizacion de todos los thread para poder seguir ejecutando
	pthread_join(th_torneo, NULL);
	pthread_join(th_dibujar, NULL);
	pthread_join(th_capturar_teclas, NULL);

	return 0;

}


void  sdl_presentacion() {

	//De esta forma me aseguro que al cerrarse el programa se cierren tambien todos los subsitemas de SDL
	atexit(SDL_Quit);

	/* incio SDL */
	// inicializar SDL
	SDL_inicializar();

	/* Cargo la imagen de presentacion */
	char imagen[40] = "../img/presentacion.jpg";
	presentacion = SDL_cargar_imagen(imagen);

	/*Inicializo el modo de video con una pantalla de 640 x 480 con 32 bytes de profundidad de color */
	pantalla = SDL_inicializar_modo_video(WIDTH, HEIGHT, BPP);

	/* Dibujamos la imagen de presentacion */
	src_pres = SDL_dibujar_imagen_src(presentacion, 0, 0);
	dest_pres = SDL_dibujar_imagen_dest(presentacion, 0, 0);

	SDL_BlitSurface(presentacion, &src_pres, pantalla, &dest_pres);

	// Actualiza una superficie
	SDL_Flip(pantalla);

	// se queda esperando a que se presione ENTER para enviar
	int done = 0;
	while (!done) {
		SDL_WaitEvent(&evento_presentacion); // se queda esperando por algun evento. no consume cpu
		SDL_PollEvent(&evento_presentacion);  // cola de eventos

		if (evento_presentacion.type == SDL_KEYDOWN) // detecta si se presiono una tecla
				{
			if (evento_presentacion.key.keysym.sym == SDLK_RETURN)
				done = 1;
			if (evento_presentacion.key.keysym.sym == SDLK_ESCAPE)
				exit(0);
		}
	}

} // fin sdl_presentacion


void * th_f_torneo(void * nombre_jug) {

	sdl_esperando_inscripcion();



	 // creacion del socket  envia nombre de jugador, se anota al torneo y espera a la respuesta del servidor de torneo
	  socket_ST = socket_creacion();

	 // conectar con el servidor
	  socket_conectar_servidorST(socket_ST);

	 // Enviamos el mensaje
	 strncpy(buffer,(char*) nombre_jug, TAMBUF);

	 send(socket_ST, nombre_jug, TAMBUF, 0);

	 // recibo respuesta: Puedo jugar o no
	 recv(socket_ST, nombre_jug, TAMBUF, 0);


	 // Cerramos el socket como corresponde.
	 //    close(socket_fd);


	 // desbloquea a th_dibujar
	 if(strcmp((char*)nombre_jug,"OK") == 0)   // empezar a jugar
	 	 pthread_cond_broadcast(&cond_dibujar);
	 else{
		exit(0);
	 }



}

void* th_f_dibujar(void *) {
	// espera bloqueante a que th_torneo le envie la condicion de desbloqueo

//	pthread_mutex_lock(&mutex);
//

	pthread_cond_wait(&cond_dibujar, &mutex);

	// socket para dibujar la posicion inicial
	listen_socket_SP = crear_socket_SP();

        ofstream salida("salida.txt");
        
	int tam, i;
	char ack[15];
        char msg[30];
        int cant_objetos = 4;
	// se crean los jugadores
	sock_aceptar = accept(listen_socket_SP, (struct sockaddr *) (&con_address), &con_addr_len);

	SDL_FreeSurface(presentacion);


            dibujar_fondo();
               
	    SDL_Flip(pantalla);

            for(i=0;i<cant_objetos;i++){
		tam = recv(sock_aceptar, (void*) &recepcion[i], sizeof(recepcion), 0);
            //        fflush(stdout);

                      send(sock_aceptar,ack,sizeof(ack),0);
            }

            carga_inicial();  //dibuja los objetos iniciales

            char tecla[2];
            int j=0;
            while(1){

		recv(sock_aceptar, (void*) &recepcion_juego, sizeof(recepcion), 0);

        //        salida<<j<<endl;
                j++;
                dibujar_fondo();
            	   
                for(i=0;i<cant_objetos;i++)
                {
                   if(strcmp(recepcion_juego.identificador,recepcion[i].identificador)==0){
                      if(strcmp(recepcion_juego.tecla,"A")==0)
                         recepcion[i].y -=10;
                      if(strcmp(recepcion_juego.tecla,"B")==0)
                         recepcion[i].x -=10;
                      if(strcmp(recepcion_juego.tecla,"C")==0)
                         recepcion[i].y +=10;
                      if(strcmp(recepcion_juego.tecla,"D")==0)
                         recepcion[i].x +=10;
                   }
                   

               } 
                   carga_inicial();
                   if(j==0)
                     SDL_Flip(pantalla);
          }  // fin while
            


	close(sock_aceptar);
        pthread_exit(NULL);
	return (void*)NULL;
}

void dibujar_movimiento_mario(void) {

	char imagen[50];
	if (!strcmp(tecla, "SDLK_DOWN")) {
		mario_movi.y += 10;
		if (mario_movi.y <= HEIGHT - MARIO_H)
			dest_mario = SDL_dibujar_imagen_dest(mario, mario_movi.x,mario_movi.y);
		else
			mario_movi.y -= 10;

		strcpy(imagen, "../img/mario_subida2.png");
		mario = SDL_cargar_imagen(imagen);
		refrescar_pantalla_mario();
		usleep(70000);

		strcpy(imagen, "../img/mario_subida1.png");
		mario = SDL_cargar_imagen(imagen);
		refrescar_pantalla_mario();
		usleep(70000);
	}

	if (!strcmp(tecla, "SDLK_UP")) {
		mario_movi.y -= 10;
		if (mario_movi.y >= 0)
			dest_mario = SDL_dibujar_imagen_dest(mario, mario_movi.x,mario_movi.y);
		else
			mario_movi.y += 10;

		strcpy(imagen, "../img/mario_subida1.png");
		mario = SDL_cargar_imagen(imagen);
		refrescar_pantalla_mario();
		usleep(70000);

		strcpy(imagen, "../img/mario_subida2.png");
		mario = SDL_cargar_imagen(imagen);
		refrescar_pantalla_mario();
		usleep(70000);

	}

	if (!strcmp(tecla, "SDLK_LEFT")) {
		mario_movi.x -= 10;
		if (mario_movi.x >= 0)
			dest_mario = SDL_dibujar_imagen_dest(mario, mario_movi.x,mario_movi.y);
		else
			mario_movi.x += 10;

		strcpy(imagen, "../img/mario_izq2.png");
		mario = SDL_cargar_imagen(imagen);
		refrescar_pantalla_mario();
		usleep(10000);

		strcpy(imagen, "../img/mario_izq3.png");
		mario = SDL_cargar_imagen(imagen);
		refrescar_pantalla_mario();
		usleep(10000);

		strcpy(imagen, "../img/mario_izq1.png");
		mario = SDL_cargar_imagen(imagen);
		refrescar_pantalla_mario();
		usleep(10000);

	}

	if (!strcmp(tecla, "SDLK_RIGHT")) {
		mario_movi.x += 10;
		if (mario_movi.x <= WIDTH - MARIO_W)  // se lo resta al ancho de mario
			dest_mario = SDL_dibujar_imagen_dest(mario, mario_movi.x,mario_movi.y);
		else
			mario_movi.x -= 10;

		strcpy(imagen, "../img/mario_der2.png");
		mario = SDL_cargar_imagen(imagen);
		refrescar_pantalla_mario();
		usleep(10000);

		strcpy(imagen, "../img/mario_der3.png");
		mario = SDL_cargar_imagen(imagen);
		refrescar_pantalla_mario();
		usleep(10000);

		strcpy(imagen, "../img/mario_der1.png");
		mario = SDL_cargar_imagen(imagen);
		refrescar_pantalla_mario();
		usleep(10000);
	}

}


// luego de dibujar el movimiento de mario se debe refrescar la pantalla
void refrescar_pantalla_mario(void) {

	SDL_BlitSurface(fondo, &src_fondo, pantalla, &dest_fondo);
	SDL_BlitSurface(mario, &src_mario, pantalla, &dest_mario);
	SDL_Flip(pantalla);

}


void sdl_esperando_inscripcion(void) {

	SDL_Color bgcolor, fgcolor;
	SDL_Rect rectangulo;
	SDL_Surface *ttext;
	TTF_Font *fuente;

	const char texto[20] = "Esperando ...";
	char msg[20];

	// imagen que espera a que el server de torneo lo inscriba
	char imagen[128] = "../img/esperando.jpg";
	esperando = SDL_cargar_imagen(imagen);

	src_pres = SDL_dibujar_imagen_src(esperando, 0, 0);
	dest_pres = SDL_dibujar_imagen_dest(esperando, 0, 0);

	SDL_BlitSurface(esperando, &src_pres, pantalla, &dest_pres);

	SDL_Flip(pantalla);

	// Inicializamos SDL_ttf
	if (TTF_Init() < 0) {
		printf("No se pudo iniciar SDL_ttf: %s\n", SDL_GetError());
		exit(0);
	}

	atexit(TTF_Quit);

	// carga la fuente de letra
	fuente = TTF_OpenFont("BRLNSR.ttf", 20);

	// inicializa colores para el texto
	fgcolor.r = 200;
	fgcolor.g = 200;
	fgcolor.b = 10;

	bgcolor.r = 255;
	bgcolor.g = 0;
	bgcolor.b = 0;

	sprintf(msg, "%s", texto);
	ttext = TTF_RenderText_Shaded(fuente, msg, fgcolor, bgcolor);

	// posicion del texto esperando ...
	rectangulo.y = 440;
	rectangulo.x = 300;
	rectangulo.w = ttext->w;
	rectangulo.h = ttext->h;

	// Usamos color rojo para la transparencia del fondo
	SDL_SetColorKey(ttext, SDL_SRCCOLORKEY | SDL_RLEACCEL,
			SDL_MapRGB(ttext->format, 255, 0, 0));

	// Volcamos la superficie a la pantalla
	SDL_BlitSurface(ttext, NULL, pantalla, &rectangulo);

	// destruimos la fuente de letra
	TTF_CloseFont(fuente);

	// liberar superficie
	SDL_FreeSurface(ttext);

	SDL_Flip(pantalla);

	SDL_Delay(1000);
	// recv.... al servidor de torneo

}



void* th_f_capturar_teclas(void *) {

//	pthread_mutex_lock(&mutex);
//	pthread_cond_wait(&cond_capturar_tecla, &mutex);

	Uint8 *keys;
	keys = SDL_GetKeyState(NULL);
	int done = 0;
        char ack[5];
        char tecla[2];

	// activar repeticion de teclas
	SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);


	while (!done) {
		SDL_WaitEvent(&evento_mario);
		SDL_PollEvent(&evento_mario);
		if (evento_mario.type == SDL_KEYDOWN) // detecta si se presiono una tecla
                {

			if(evento_mario.key.keysym.sym == SDLK_DOWN) {

					strcpy(tecla,"C");
			}

			if (evento_mario.key.keysym.sym == SDLK_UP) {
					strcpy(tecla,"A");

			}
			if (evento_mario.key.keysym.sym == SDLK_LEFT) {
					strcpy(tecla, "B");

			}

			if (evento_mario.key.keysym.sym == SDLK_RIGHT) {
					strcpy(tecla, "D");


			}

			if (evento_mario.key.keysym.sym == SDLK_ESCAPE)
                        {
                             close(sock_aceptar);
                             close(listen_socket_SP);
				exit(0);
                        }

			send(sock_aceptar,tecla, sizeof(tecla), 0); // envia la tecla el servidor de partida

		} // fin if
	}  // fin while
}

void dibujar_fondo(void) {

	char imagen[128];
	strcpy(imagen, "../img/fondo.png");
	fondo = SDL_cargar_imagen(imagen);

	/* Dibujamos la imagen de fondo */
	src_fondo = SDL_dibujar_imagen_src(fondo, 0, 0);
	dest_fondo = SDL_dibujar_imagen_dest(fondo, 0, 0);

	SDL_BlitSurface(fondo, &src_fondo, pantalla, &dest_fondo);
     //   SDL_Flip(pantalla);
}

void carga_inicial()
{
     int cant_objetos = 4;
     int i;
   
           for(i=0;i<cant_objetos;i++){

	        mario = SDL_cargar_imagen(imagenes[i]);
		
		mario_movi.x = recepcion[i].x;
		mario_movi.y = recepcion[i].y;

		src_mario = SDL_dibujar_imagen_src(mario, 0, 0);
		dest_mario = SDL_dibujar_imagen_dest(mario, mario_movi.x,mario_movi.y);


	 	SDL_BlitSurface(mario, &src_mario, pantalla, &dest_mario);

//                SDL_Flip(pantalla);
	} // fin for
        SDL_Flip(pantalla);

}
